#include <rclcpp/rclcpp.hpp>
#include <rclcpp/parameter_client.hpp>
#include <future>
#include <thread>

class ParameterReaderNode : public rclcpp::Node {
public:
    ParameterReaderNode() : Node("parameter_reader") {
        param_client_node_ = std::make_shared<rclcpp::Node>("param_client_node");
        // 创建异步参数客户端
        param_client_ = std::make_shared<rclcpp::AsyncParametersClient>(
            param_client_node_, "add_on_set_node");
        
        // 使用定时器定期获取参数
        timer_ = this->create_wall_timer(
            std::chrono::seconds(2),
            std::bind(&ParameterReaderNode::timer_callback, this));
        
        // 异步获取单个参数
        // async_get_single_parameter();
        // std::thread{&ParameterReaderNode::async_get_single_parameter, this}.detach();
    }

private:
    rclcpp::AsyncParametersClient::SharedPtr param_client_;
    rclcpp::Node::SharedPtr param_client_node_;
    rclcpp::TimerBase::SharedPtr timer_;

    void timer_callback() {
        if (!param_client_->service_is_ready()) {
            RCLCPP_WARN(this->get_logger(), "Parameter service not ready");
            return;
        }
        
        // 异步获取参数列表
        async_get_all_parameters();
    }

    void async_get_all_parameters() {
        // 异步列出参数
        auto list_future = param_client_->list_parameters({"name", "age", "height", "camera", "motor"}, 0);
        
        if (rclcpp::spin_until_future_complete(param_client_node_, list_future) !=rclcpp::FutureReturnCode::SUCCESS){
            RCLCPP_ERROR(this->get_logger(), "service call failed, exiting tutorial.");
            return;
        }
        //RCLCPP_INFO(this->get_logger(), "list_future Call list Wait for parameters ...");
        auto param_names = list_future.get();      
        // 为每个参数创建异步获取请求
        for (const auto& name : param_names.names) {
            async_get_parameter(name);
        }
    }

    void async_get_parameter(const std::string& name) {
        // 异步获取单个参数
        auto get_future = param_client_->get_parameters({name});
        if (rclcpp::spin_until_future_complete(param_client_node_, get_future) !=rclcpp::FutureReturnCode::SUCCESS){
            RCLCPP_ERROR(this->get_logger(), "service call failed, exiting tutorial.");
            return;
        }
        auto params = get_future.get();
        if (!params.empty()) {
            const auto& param = params[0];
            // 根据参数类型输出
            switch (param.get_type()) {
                case rclcpp::ParameterType::PARAMETER_STRING:
                    RCLCPP_INFO(this->get_logger(), "Parameter %s: %s", 
                                name.c_str(), param.as_string().c_str());
                    break;
                case rclcpp::ParameterType::PARAMETER_INTEGER:
                    RCLCPP_INFO(this->get_logger(), "Parameter %s: %ld", 
                                name.c_str(), param.as_int());
                    break;
                case rclcpp::ParameterType::PARAMETER_DOUBLE:
                    RCLCPP_INFO(this->get_logger(), "Parameter %s: %f", 
                                name.c_str(), param.as_double());
                    break;
                case rclcpp::ParameterType::PARAMETER_BOOL:
                    RCLCPP_INFO(this->get_logger(), "Parameter %s: %s", 
                                name.c_str(), param.as_bool() ? "true" : "false");
                    break;
                default:
                    RCLCPP_INFO(this->get_logger(), "Parameter %s: %s", 
                                name.c_str(), param.value_to_string().c_str());
                    break;
            }
        }
}

    void async_get_single_parameter() {
        while(!param_client_->service_is_ready()) {
            RCLCPP_WARN(this->get_logger(), "Parameter service not ready, retrying...");
        }

        RCLCPP_INFO(this->get_logger(), "Waiting for parameters asynchronously...");
        // 异步获取单个参数
        auto future = param_client_->get_parameters({"name"});
        RCLCPP_INFO(this->get_logger(), "Call get Wait for parameters ...");
        // 事件循环处理param_client_node_节点的事件，直到future完成,必须要使用rclcpp::spin_until_future_complete开启节点的事件循环，
        // 否则无法处理事件响应
        if (rclcpp::spin_until_future_complete(param_client_node_, future) !=rclcpp::FutureReturnCode::SUCCESS){
            RCLCPP_ERROR(this->get_logger(), "service call failed, exiting tutorial.");
            return;
        }
        auto params = future.get();
        if (!params.empty() && params.front().get_type() == rclcpp::ParameterType::PARAMETER_STRING) {
            RCLCPP_INFO(this->get_logger(), "Parameter name: %s", params.front().as_string().c_str());
        } else {
            RCLCPP_WARN(this->get_logger(), "Parameter 'name' not found or wrong type");
        }
        RCLCPP_INFO(this->get_logger(), "Got parameters asynchronously.");
    }
};

int main(int argc, char** argv) {
    rclcpp::init(argc, argv);
    auto node = std::make_shared<ParameterReaderNode>();
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}